package config

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
)

// ConfigWatcher 配置文件监控器
type ConfigWatcher struct {
	configPath   string
	watcher      *fsnotify.Watcher
	mu           sync.RWMutex
	config       *Config
	lastModified time.Time
	callbacks    []ConfigChangeCallback
	running      bool
	stopCh       chan struct{}
}

// ConfigChangeCallback 配置变化回调函数类型
type ConfigChangeCallback func(oldConfig, newConfig *Config) error

// NewConfigWatcher 创建配置文件监控器
func NewConfigWatcher(configPath string) (*ConfigWatcher, error) {
	// 创建 fsnotify watcher
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, fmt.Errorf("创建文件监控器失败: %v", err)
	}

	// 如果配置文件路径为空，查找默认配置文件
	if configPath == "" {
		configPath = FindDefaultConfig()
		if configPath == "" {
			watcher.Close()
			return nil, fmt.Errorf("未找到默认配置文件")
		}
	}

	// 获取配置文件的绝对路径
	absPath, err := filepath.Abs(configPath)
	if err != nil {
		watcher.Close()
		return nil, fmt.Errorf("获取配置文件绝对路径失败: %v", err)
	}

	// 检查配置文件是否存在
	if _, err := os.Stat(absPath); os.IsNotExist(err) {
		watcher.Close()
		return nil, fmt.Errorf("配置文件不存在: %s", absPath)
	}

	// 获取文件修改时间
	stat, err := os.Stat(absPath)
	if err != nil {
		watcher.Close()
		return nil, fmt.Errorf("获取文件信息失败: %v", err)
	}

	cw := &ConfigWatcher{
		configPath:   absPath,
		watcher:      watcher,
		lastModified: stat.ModTime(),
		callbacks:    make([]ConfigChangeCallback, 0),
		stopCh:       make(chan struct{}),
	}

	// 添加主配置文件到监控
	if err := watcher.Add(absPath); err != nil {
		watcher.Close()
		return nil, fmt.Errorf("添加文件到监控失败: %v", err)
	}

	// 添加进程配置文件目录到监控
	processesDir := filepath.Join(filepath.Dir(absPath), "processes")
	if _, err := os.Stat(processesDir); err == nil {
		if err := watcher.Add(processesDir); err != nil {
			fmt.Printf("[CONFIG] 添加进程配置目录到监控失败: %v\n", err)
		} else {
			fmt.Printf("[CONFIG] 开始监控进程配置目录: %s\n", processesDir)
		}
	}

	// 加载初始配置
	config, err := cw.loadConfig()
	if err != nil {
		watcher.Close()
		return nil, fmt.Errorf("加载初始配置失败: %v", err)
	}
	cw.config = config

	return cw, nil
}

// AddCallback 添加配置变化回调
func (cw *ConfigWatcher) AddCallback(callback ConfigChangeCallback) {
	cw.mu.Lock()
	defer cw.mu.Unlock()
	cw.callbacks = append(cw.callbacks, callback)
}

// GetConfig 获取当前配置
func (cw *ConfigWatcher) GetConfig() *Config {
	cw.mu.RLock()
	defer cw.mu.RUnlock()
	return cw.config
}

// Start 开始监控配置文件变化
func (cw *ConfigWatcher) Start() error {
	cw.mu.Lock()
	if cw.running {
		cw.mu.Unlock()
		return fmt.Errorf("配置监控器已经在运行中")
	}
	cw.running = true
	cw.mu.Unlock()

	fmt.Printf("[CONFIG] 开始监控配置文件: %s\n", cw.configPath)

	go cw.watch()
	return nil
}

// Stop 停止监控
func (cw *ConfigWatcher) Stop() {
	cw.mu.Lock()
	defer cw.mu.Unlock()

	if !cw.running {
		return
	}

	cw.running = false
	close(cw.stopCh)
	cw.watcher.Close()

	fmt.Println("[CONFIG] 配置文件监控已停止")
}

// watch 监控文件变化
func (cw *ConfigWatcher) watch() {
	defer cw.watcher.Close()

	for {
		select {
		case event, ok := <-cw.watcher.Events:
			if !ok {
				return
			}

			// 处理主配置文件的变化
			if event.Name == cw.configPath {
				if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Rename == fsnotify.Rename {
					cw.handleConfigChange()
				}
			} else {
				// 处理进程配置文件目录中的变化
				processesDir := filepath.Join(filepath.Dir(cw.configPath), "processes")
				if strings.HasPrefix(event.Name, processesDir) {
					if event.Op&fsnotify.Write == fsnotify.Write ||
						event.Op&fsnotify.Rename == fsnotify.Rename ||
						event.Op&fsnotify.Create == fsnotify.Create ||
						event.Op&fsnotify.Remove == fsnotify.Remove {
						fmt.Printf("[CONFIG] 检测到进程配置文件变化: %s\n", event.Name)
						cw.handleConfigChange()
					}
				}
			}

		case err, ok := <-cw.watcher.Errors:
			if !ok {
				return
			}
			fmt.Printf("[CONFIG] 配置文件监控错误: %v\n", err)

		case <-cw.stopCh:
			return
		}
	}
}

// handleConfigChange 处理配置变化
func (cw *ConfigWatcher) handleConfigChange() {
	// 检查文件是否真的发生了变化
	stat, err := os.Stat(cw.configPath)
	if err != nil {
		fmt.Printf("[CONFIG] 检查配置文件状态失败: %v\n", err)
		return
	}

	// 如果修改时间没有变化，忽略
	if stat.ModTime().Equal(cw.lastModified) {
		return
	}

	// 等待文件写入完成（避免文件正在写入时读取）
	time.Sleep(100 * time.Millisecond)

	// 备份当前配置
	if err := cw.backupConfig(); err != nil {
		fmt.Printf("[CONFIG] 备份配置文件失败: %v\n", err)
	}

	// 加载新配置
	newConfig, err := cw.loadConfig()
	if err != nil {
		fmt.Printf("[CONFIG] 重新加载配置失败: %v\n", err)
		// 如果新配置加载失败，尝试回滚
		if rollbackErr := cw.rollbackConfig(); rollbackErr != nil {
			fmt.Printf("[CONFIG] 回滚配置失败: %v\n", rollbackErr)
		} else {
			fmt.Printf("[CONFIG] 已回滚到备份配置\n")
		}
		return
	}

	// 更新修改时间
	cw.lastModified = stat.ModTime()

	// 保存旧配置
	cw.mu.RLock()
	oldConfig := cw.config
	cw.mu.RUnlock()

	// 更新配置
	cw.mu.Lock()
	cw.config = newConfig
	cw.mu.Unlock()

	fmt.Printf("[CONFIG] 配置文件已更新: %s\n", cw.configPath)

	// 调用所有回调函数
	cw.mu.RLock()
	callbacks := make([]ConfigChangeCallback, len(cw.callbacks))
	copy(callbacks, cw.callbacks)
	cw.mu.RUnlock()

	for _, callback := range callbacks {
		if err := callback(oldConfig, newConfig); err != nil {
			fmt.Printf("[CONFIG] 配置变化回调执行失败: %v\n", err)
		}
	}
}

// loadConfig 加载配置文件
func (cw *ConfigWatcher) loadConfig() (*Config, error) {
	loader := NewConfigLoader(cw.configPath)
	return loader.Load()
}

// backupConfig 备份配置文件
func (cw *ConfigWatcher) backupConfig() error {
	// 创建备份目录
	backupDir := filepath.Join(filepath.Dir(cw.configPath), "backups")
	if err := os.MkdirAll(backupDir, 0755); err != nil {
		return fmt.Errorf("创建备份目录失败: %v", err)
	}

	// 生成备份文件名（包含时间戳）
	timestamp := time.Now().Format("20060102_150405")
	backupPath := filepath.Join(backupDir, fmt.Sprintf("config_backup_%s.yaml", timestamp))

	// 复制配置文件到备份目录
	sourceFile, err := os.Open(cw.configPath)
	if err != nil {
		return fmt.Errorf("打开源配置文件失败: %v", err)
	}
	defer sourceFile.Close()

	backupFile, err := os.Create(backupPath)
	if err != nil {
		return fmt.Errorf("创建备份文件失败: %v", err)
	}
	defer backupFile.Close()

	_, err = backupFile.ReadFrom(sourceFile)
	if err != nil {
		return fmt.Errorf("复制配置文件失败: %v", err)
	}

	fmt.Printf("[CONFIG] 配置文件已备份到: %s\n", backupPath)
	return nil
}

// rollbackConfig 回滚配置文件
func (cw *ConfigWatcher) rollbackConfig() error {
	// 查找最新的备份文件
	backupDir := filepath.Join(filepath.Dir(cw.configPath), "backups")
	backupFiles, err := filepath.Glob(filepath.Join(backupDir, "config_backup_*.yaml"))
	if err != nil {
		return fmt.Errorf("查找备份文件失败: %v", err)
	}

	if len(backupFiles) == 0 {
		return fmt.Errorf("没有找到备份文件")
	}

	// 按文件名排序，获取最新的备份
	var latestBackup string
	for _, backup := range backupFiles {
		if backup > latestBackup {
			latestBackup = backup
		}
	}

	// 复制备份文件到原位置
	backupFile, err := os.Open(latestBackup)
	if err != nil {
		return fmt.Errorf("打开备份文件失败: %v", err)
	}
	defer backupFile.Close()

	configFile, err := os.Create(cw.configPath)
	if err != nil {
		return fmt.Errorf("创建配置文件失败: %v", err)
	}
	defer configFile.Close()

	_, err = configFile.ReadFrom(backupFile)
	if err != nil {
		return fmt.Errorf("恢复配置文件失败: %v", err)
	}

	fmt.Printf("[CONFIG] 已从备份恢复配置: %s\n", latestBackup)
	return nil
}

// IsRunning 检查是否在运行
func (cw *ConfigWatcher) IsRunning() bool {
	cw.mu.RLock()
	defer cw.mu.RUnlock()
	return cw.running
}
